package com.asiainfo.simpledao;

import java.io.Closeable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class JdbcUtil {

	public static PreparedStatement getPreparedStatement(Connection conn, String sql) throws SQLException {
		PreparedStatement ps = null;
		ps = conn.prepareStatement(sql);
		return ps;
	}

	public static Statement getStatement(Connection conn) throws SQLException {
		Statement sta = conn.createStatement();
		return sta;
	}

	public static ResultSet queryForResultSet(Connection conn, String sql, Object... params) throws SQLException {
		PreparedStatement ps = getPreparedStatement(conn, sql);
		if (params != null && params.length > 0) {
			for (int i = 0; i < params.length; i++) {
				ps.setObject(i + 1, params[i]);
			}
		}
		return ps.executeQuery();
	}

	public static ResultSet queryForResultSet(Connection conn, String nameParameterSql, Map<String, Object> params) throws SQLException {
		NameParameterSqlParser sqlParser = new NameParameterSqlParser(nameParameterSql);
		PreparedStatement ps = getPreparedStatement(conn, sqlParser.getUseSql());
		fillParameter(ps, sqlParser, params);
		return ps.executeQuery();
	}

	private static void fillParameter(PreparedStatement ps, NameParameterSqlParser sqlParser, Map<String, Object> params) throws SQLException {
		List<String> parameterNames = sqlParser.getParameterNames();
		if (parameterNames != null && parameterNames.size() > 0) {
			int i = 1;
			for (String parameterName : parameterNames) {
				ps.setObject(i++, params.get(parameterName));
			}
		}
	}

	public static int execSQL(Connection conn, String sql, Object... params) throws SQLException {
		PreparedStatement ps = null;
		try {
			ps = getPreparedStatement(conn, sql);
			if (params != null && params.length > 0) {
				int i = 1;
				for (Object param : params) {
					ps.setObject(i++, param);
				}
			}
			return ps.executeUpdate();
		} finally {
			close(ps);
		}
	}

	public static int execSQL(Connection conn, String nameParameterSql, Map<String, Object> params) throws SQLException {
		PreparedStatement ps = null;
		try {
			NameParameterSqlParser sqlParser = new NameParameterSqlParser(nameParameterSql);
			ps = getPreparedStatement(conn, sqlParser.getUseSql());
			fillParameter(ps, sqlParser, params);
			return ps.executeUpdate();
		} finally {
			close(ps);
		}
	}

	public static List<Row> getRows(ResultSet rs) throws SQLException {
		List<Row> ret = new ArrayList<Row>();
		List<String> rsColNames = new ArrayList<String>();
		if (rs != null) {
			while (rs.next()) {
				rsColNames = getColumns(rs);
				Row line = new Row();
				for (int i = 0; i < rsColNames.size(); ++i) {
					line.put(rsColNames.get(i).toString(), rs.getObject(rsColNames.get(i).toString()));
				}
				ret.add(line);
			}
			return ret;
		}
		return null;
	}

	public static Row getRow(ResultSet rs) throws SQLException {
		List<String> rsColNames = new ArrayList<String>();
		if ((rs != null) && (rs.next())) {
			rsColNames = getColumns(rs);
			Row line = new Row();
			for (int i = 0; i < rsColNames.size(); ++i) {
				line.put(rsColNames.get(i).toString(), rs.getObject(rsColNames.get(i).toString()));
			}
			return line;
		}
		return null;
	}

	private static List<String> getColumns(ResultSet rs) throws SQLException {
		List<String> ret = new ArrayList<String>();
		ResultSetMetaData rsmd = rs.getMetaData();
		int k = rsmd.getColumnCount();
		for (int i = 1; i <= k; ++i) {
			ret.add(rsmd.getColumnName(i));
		}
		return ret;
	}

	public static void close(ResultSet rs) {
		try {
			if (rs != null)
				rs.close();
		} catch (SQLException ex) {
		}
	}

	public static void close(Statement ps) {
		try {
			if (ps != null)
				ps.close();
		} catch (SQLException ex) {
		}
	}

	public static void close(Connection conn) {
		try {
			if (conn != null)
				conn.close();
		} catch (SQLException ex) {
		}
	}

	public static void rollback(Connection conn) {
		try {
			if (conn != null)
				conn.rollback();
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}
	}

	public static void commit(Connection conn) {
		try {
			if (conn != null)
				conn.commit();
		} catch (SQLException ex) {
			throw new RuntimeException(ex);
		}
	}

	public static void closeAll(Object... closes) {
		if (closes == null || closes.length == 0)
			return;
		for (Object close : closes) {
			try {
				if (close instanceof Closeable) {
					((Closeable) close).close();
				} else {
					close.getClass().getMethod("close").invoke(close);
				}
			} catch (Exception e) {
			}
		}
	}

}
